﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using LASDesktop.Classes;
using LASDesktop.LASDBClasses;

namespace LASDesktop.ModuloCompras
{

    #region Structs

    public struct GridStruct
    {
        public List<Articulo> ComboArticulos { get; set; }
        public Articulo ArticuloNuevo { get; set; }
        public List<Bodega> ComboBodegas { get; set; }
        public Bodega BodegaFinal { get; set; }
        public Decimal Impuesto { get; set; }
        public int Cantidad { get; set; }
        public Decimal PrecioDeCompra { get; set; }
        public Decimal Total
        {
            get { return Decimal.Truncate((PrecioDeCompra * Cantidad * 100) / 100); }
        }
    }

    public struct PendingStruct
    {
        public DatosDocumentosCompra DatosDocumentos { get; set; }
        public String CodigoUnico { get; set; }
    } 

    public struct InsertProduct
    {
        public int IdArticulo { get; set; }
        public int IdBodega { get; set; }
        public int Cantidad { get; set; }
        public decimal Impuesto { get; set; }
        public decimal PrecioCompra { get; set; }
    }
    
    #endregion

    /// <summary>
    /// Interaction logic for ModuloCompras.xaml
    /// </summary>
    public partial class ModuloCompras
    {

        private LASDBDataContext _db = new LASDBDataContext();
        private int _companyId = 1;
        private int _canUserEdit;
        private readonly List<Bodega> _bodegas;
        private readonly List<Articulo> _articulos;
        private List<GridStruct> _gridDocumentSource = new List<GridStruct>();
        private List<PendingStruct> _pendingDocuments = new List<PendingStruct>();
        private List<Socio> _listaSocios;
        private List<Moneda> _listaMonedas;
        private Login _parent;
        private PendingStruct _currentStruct;


        public ModuloCompras(Login parent)
        {
            InitializeComponent();
            _bodegas = GetStorageRoomsFromCompany(_companyId);
            _listaSocios = LoadProveedoresSistema();
            _listaMonedas = LoadSystemCurrencies();
            ProveedorComboBox.ItemsSource = _listaSocios;
            MonedaComboBox.ItemsSource = _listaMonedas;
            FechaContabilizacionDatePicker.SelectedDate = DateTime.Now;
            _articulos = (List<Articulo>) GetProductsFromCompany(_companyId);
            _parent = parent;
        }
        
        #region GUI Documentos Pendientes

        #region GUI Pendientes

        #region Eventos del GUI

        private void NuevoDocumentoButtonClick(object sender, MouseButtonEventArgs e)
        {
            if (InputTipoDeDocumento.SelectedIndex < 0) return;
            
            Pendientes.Visibility = Visibility.Collapsed;
            EnableInput();
            LoadDocumentTemplate(InputTipoDeDocumento.SelectedIndex);
            Documento.Visibility = Visibility.Visible;
        }

        private void VerDetallesButtonClick(object sender, MouseButtonEventArgs e)
        {
            try
            {
                Pendientes.Visibility = Visibility.Collapsed;
                DisableInput();
                _currentStruct = (PendingStruct)GridPendientes.SelectedItem;
                LoadDocumentTemplate(InputTipoDeDocumento.SelectedIndex);
                LoadDocumentData(_currentStruct);
                Documento.Visibility = Visibility.Visible;
            }
            catch (Exception)
            {
                MessageBox.Show("Seleccione una fila primero");
            }
        }

        private void DocumentTypeComboChanged(object sender, SelectionChangedEventArgs e)
        {
            LoadPendingDocuments(InputTipoDeDocumento.SelectedIndex);
        }
        #endregion

        #region Métodos de Actualización del GUI
        private void LoadPendingDocuments(int documentType)
        {
            switch (documentType)
            {
                case Constants.DOCUMENT_TYPE_OC:
                    _pendingDocuments = OcPendingStruct(_companyId);
                    break;
                case Constants.DOCUMENT_TYPE_EM:
                    _pendingDocuments = EmPendingStruct(_companyId);
                    break;
                case Constants.DOCUMENT_TYPE_FP:
                    _pendingDocuments = FpPendingStruct(_companyId);
                    break;
            }

            GridPendientes.ItemsSource = _pendingDocuments;
        }
        #endregion

        #endregion

        #region GUI Documento

        #region Métodos de actualización del GUI
        /// <summary>
        /// Método que actualiza el formato del GUI de documento según el tipo de documento
        /// </summary>
        /// <param name="documentType"></param>
        private void LoadDocumentTemplate(int documentType)
        {
            //Se limpian ambos grid en caso de que haya información previa
            _gridDocumentSource = new List<GridStruct>();
            GridArticulos.ItemsSource = _gridDocumentSource;
            LoadNewProducts(GridArticulos);

            var source = new List<String> {Constants.PURCHASES_TRANSFORM_DEFAULT};

            //Se le da formato a la ventana según el tipo de documento
            switch (documentType)
            {
                case Constants.DOCUMENT_TYPE_OC:
                    TextFecha.Content = "Fecha de Entrega:";
                    source.Add(Constants.PURCHASES_TRANSFORM_EM);
                    source.Add(Constants.PURCHASES_TRANSFORM_FP);
                    break;
                case Constants.DOCUMENT_TYPE_EM:
                    TextFecha.Content = "Fecha de Vencimiento:";
                    source.Add(Constants.PURCHASES_TRANSFORM_FP);
                    break;
                case Constants.DOCUMENT_TYPE_FP:
                    TextFecha.Content = "Fecha de Vencimiento:";
                    break;
            }
            TransformToComboBox.SelectedIndex = 0;
            TransformToComboBox.ItemsSource = source;
        }

        /// <summary>
        /// Método que habilita el modo de trasformar documento y deshabilita la edición del documento
        /// </summary>
        private void DisableInput()
        {
            ProveedorComboBox.IsEnabled = false;
            MonedaComboBox.IsEnabled = false;
            FechaEntregaDatePicker.IsEnabled = false;
            FechaContabilizacionDatePicker.IsEnabled = false;
            EmpleadoComboBox.IsEnabled = false;
            _canUserEdit = Constants.GRID_TYPE_CANT_EDIT;
            TransformToComboBox.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Método que habilita el modo de crear documento y deshabilita la opción de transformar
        /// </summary>
        private void EnableInput()
        {
            ProveedorComboBox.IsEnabled = true;
            ProveedorComboBox.SelectedIndex = -1;
            NombreTextBox.Text = "";
            MonedaComboBox.IsEnabled = true;
            MonedaComboBox.SelectedIndex = -1;
            FechaEntregaDatePicker.IsEnabled = true;
            FechaContabilizacionDatePicker.IsEnabled = true;
            EmpleadoComboBox.IsEnabled = false;
            EmpleadoComboBox.SelectedIndex = -1;
            _canUserEdit = Constants.GRID_TYPE_CAN_EDIT;
            TransformToComboBox.Visibility = Visibility.Hidden;
            LoadNewProducts(GridArticulos);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pending"></param>
        private void LoadDocumentData(PendingStruct pending)
        {
            ProveedorComboBox.SelectedIndex = _listaSocios.FindIndex(e => e.IdSocio == pending.DatosDocumentos.Socio.IdSocio);
            NombreTextBox.Text = pending.DatosDocumentos.Socio.Nombre;
            MonedaComboBox.SelectedIndex = _listaMonedas.FindIndex(e => e.IdMoneda == pending.DatosDocumentos.IdMoneda);    
            EmpleadoComboBox.SelectedIndex = -1;
            FechaContabilizacionDatePicker.SelectedDate = pending.DatosDocumentos.FechaContabilizacion;
            FechaEntregaDatePicker.SelectedDate = pending.DatosDocumentos.FechaEntrega;

            _gridDocumentSource = new List<GridStruct>();

            foreach (var datosPorProducto in pending.DatosDocumentos.Documentos_has_Articulos)
            {
                var gridStruct = new GridStruct()
                                     {
                                         PrecioDeCompra = datosPorProducto.PrecioCompra,
                                         ArticuloNuevo = datosPorProducto.Articulo,
                                         BodegaFinal = datosPorProducto.Bodega,
                                         Cantidad = datosPorProducto.Cantidad,
                                         ComboArticulos = _articulos,
                                         ComboBodegas = _bodegas,
                                         Impuesto = datosPorProducto.Impuesto * 100
                                     };
                _gridDocumentSource.Add(gridStruct);
            }
            _canUserEdit = Constants.GRID_TYPE_CANT_EDIT;
            LoadNewProducts(GridArticulos);

        }
        
        /// <summary>
        /// Método que carga los productos de la lista _gridDocumentSource en el grid de documentos
        /// </summary>
        /// <param name="grid"></param>
        private void LoadNewProducts(DataGrid grid)
        {
            //Si no hay una fila vacia agrega una y verifica que el producto no se encuentra ya dentro del grid



            var ultimoArticulo = _gridDocumentSource.LastOrDefault();

            if (_gridDocumentSource.Count == 0 ||
                (ultimoArticulo.ArticuloNuevo != null &&
                ultimoArticulo.BodegaFinal != null &&
                ultimoArticulo.Cantidad > 0))
            {
                for (var articulo = 0; articulo < _gridDocumentSource.Count - 1; articulo++)
                {

                    var posibleRepetido = _gridDocumentSource[articulo];

                    if (ultimoArticulo.ArticuloNuevo.IdArticulo != posibleRepetido.ArticuloNuevo.IdArticulo ||
                        ultimoArticulo.PrecioDeCompra != posibleRepetido.PrecioDeCompra ||
                        ultimoArticulo.Impuesto != posibleRepetido.Impuesto ||
                        ultimoArticulo.BodegaFinal.IdBodega != posibleRepetido.BodegaFinal.IdBodega) continue;
                    var articuloRepetido = _gridDocumentSource[articulo];
                    articuloRepetido.Cantidad += _gridDocumentSource.LastOrDefault().Cantidad;
                    _gridDocumentSource[articulo] = articuloRepetido;
                    _gridDocumentSource.RemoveAt(_gridDocumentSource.Count - 1);
                    break;
                }

                if (_canUserEdit == Constants.GRID_TYPE_CAN_EDIT)
                {

                    var newRow = new GridStruct
                    {
                        ComboBodegas = _bodegas,
                        ComboArticulos = _articulos
                    };
                    _gridDocumentSource.Add(newRow);
                }
            }

            //Actualiza el Grid
            
            grid.ItemsSource = null;
            grid.ItemsSource = _gridDocumentSource;
            

            //Actualiza los totales

            Decimal totalSinImpuestos = 0;
            Decimal totalDeImpuestos = 0;
            _gridDocumentSource.ForEach(gridStruct => totalSinImpuestos += (gridStruct.PrecioDeCompra * gridStruct.Cantidad));
            totalSinImpuestos = Decimal.Truncate(totalSinImpuestos * 100) / 100;

            _gridDocumentSource.ForEach(gridStruct => totalDeImpuestos += ((gridStruct.PrecioDeCompra * (gridStruct.Impuesto / 100)) * gridStruct.Cantidad));
            totalDeImpuestos = Decimal.Truncate(totalDeImpuestos * 100) / 100;

            var total = totalSinImpuestos + totalDeImpuestos;

            TotalAntesImpuestoTextbox.Text = totalSinImpuestos + "";
            ImpuestoTextBox.Text = totalDeImpuestos + "";
            TotalTextBox.Text = total + "";

            // Obtiene los elementos del row en cuestion y bloquea aquellos que considere necesarios
            int blockUntil;

            if (_canUserEdit == Constants.GRID_TYPE_CAN_EDIT)
            {
                blockUntil = grid.Items.Count - 1;
            }
            else
            {
                blockUntil = grid.Items.Count;
            }

            for (int i = 0; i < blockUntil; i++)
            {
                var row = GetRow(grid, i);
                var comboboxList = GetChildObject<ComboBox>(row, new List<Visual>());
                var textboxList = GetChildObject<TextBox>(row, new List<Visual>());
                if (_canUserEdit == Constants.GRID_TYPE_CANT_EDIT)
                {
                    var buttonList = GetChildObject<Image>(row, new List<Visual>());
                    buttonList.ForEach(b => ((Image)b).Visibility = Visibility.Hidden);
                }
                comboboxList.ForEach(c => ((ComboBox)c).IsEnabled = false);
                textboxList.ForEach(t => ((TextBox)t).IsEnabled = false);
            }


        }

        private void SetNewValueInGrid<T>(DataGrid grid, ComboBox combo, String property, List<T> lista)
        {
            if (grid.SelectedIndex < 0) return;

            var indexCombo = combo.SelectedIndex;
            var indexGrid = grid.SelectedIndex;
            grid.SelectedIndex = -1;
            var articuloNuevo = _gridDocumentSource[indexGrid];
            articuloNuevo = (GridStruct)SetProperty(articuloNuevo, property, lista[indexCombo]);
            _gridDocumentSource[indexGrid] = articuloNuevo;
            LoadNewProducts(grid);
        }

        private void SetNewValueInGrid(DataGrid grid, TextBox textbox, String property, int type)
        {
            if (grid.SelectedIndex < 0) return;

            try
            {
                textbox.Foreground = new SolidColorBrush(Colors.Black);
                var indexGrid = grid.SelectedIndex;
                grid.SelectedIndex = -1;
                var articuloNuevo = _gridDocumentSource[indexGrid];
                switch (type)
                {
                    case 0:
                        {
                            var cantidad = int.Parse(textbox.Text);
                            articuloNuevo = (GridStruct)SetProperty(articuloNuevo, property, cantidad);
                        }
                        break;
                    case 1:
                        {
                            var cantidad = Decimal.Parse(textbox.Text);
                            articuloNuevo = (GridStruct)SetProperty(articuloNuevo, property, cantidad);
                        }
                        break;
                    case 2:
                        {
                            var cantidad = Decimal.Parse(textbox.Text);
                            if (cantidad > 100) throw (new Exception());
                            articuloNuevo = (GridStruct)SetProperty(articuloNuevo, property, cantidad);
                        }
                        break;
                }
                _gridDocumentSource[indexGrid] = articuloNuevo;
                LoadNewProducts(grid);
            }
            catch
            {
                textbox.Foreground = new SolidColorBrush(Colors.Red);
            }
        }
        #endregion

        #region Eventos del GUI

        #region Eventos para el Grid de artículos
        private void ComboBoxArticulosSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SetNewValueInGrid(GridArticulos, (ComboBox)sender, "ArticuloNuevo", _articulos);
        }

        private void ComboBoxBodegasSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SetNewValueInGrid(GridArticulos, (ComboBox)sender, "BodegaFinal", _bodegas);
        }

        private void TextboxCantidadChanged(object sender, RoutedEventArgs e)
        {
            SetNewValueInGrid(GridArticulos, (TextBox)sender, "Cantidad", 0);
        }

        private void TextboxPrecioCompraChanged(object sender, RoutedEventArgs e)
        {
            SetNewValueInGrid(GridArticulos, (TextBox)sender, "PrecioDeCompra", 1);
        }

        private void DeleteButtonClicked(object sender, MouseButtonEventArgs e)
        {
            if (GridArticulos.SelectedIndex < 0) return;
            var indexGrid = GridArticulos.SelectedIndex;
            _gridDocumentSource.RemoveAt(indexGrid);
            LoadNewProducts(GridArticulos);
        }

        private void TextboxImpuestoSelectionChanged(object sender, RoutedEventArgs e)
        {
            SetNewValueInGrid(GridArticulos, (TextBox)sender, "Impuesto", 2);
        }
        #endregion

        #region Eventos Generales del GUI
        private void AcceptDocumentClick(object sender, RoutedEventArgs e)
        {
            try
            {
                var tipoDocumento = InputTipoDeDocumento.SelectedIndex;

                if (_canUserEdit == Constants.GRID_TYPE_CAN_EDIT)
                {
                    var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
                    var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
                    var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
                    var fechaEntrega = FechaEntregaDatePicker.SelectedDate;

                    if (selectedMoneyIndex == -1 || selectedMoneyIndex == -1 || selectedPartnerIndex == -1 || fechaContabilizacion == null || fechaEntrega == null)
                    {
                        MessageBox.Show("Llene todos los campos");
                        return;
                    }

                    var listaProductos = TransformGridToInsertProduct();
                    if (listaProductos.Count == 0)
                    {
                        MessageBox.Show("Debe seleccionar al menos un producto");
                        return;
                    }

                    //El usuario desea crear un nuevo tipo de documento
                    switch (tipoDocumento)
                    {
                        case Constants.DOCUMENT_TYPE_OC:
                            CreateOC(listaProductos);
                            break;
                        case Constants.DOCUMENT_TYPE_EM:
                            CreateEM(listaProductos);
                            break;
                        case Constants.DOCUMENT_TYPE_FP:
                            CreateFP(listaProductos);
                            break;
                    }
                }
                else
                {
                    //El usuario desea transformar el documento
                    var tipoDeFuturoDocumento = TransformToComboBox.SelectedIndex;

                    //Si el tipo al que se desea transformar corresponde a un valor default
                    if (tipoDeFuturoDocumento == 0)
                    {
                        //Regresa a la sección de pendientes y limpia la interfaz
                        Documento.Visibility = Visibility.Collapsed;
                        Pendientes.Visibility = Visibility.Visible;
                        InputTipoDeDocumento.SelectedIndex = -1;
                        GridPendientes.ItemsSource = new List<PendingStruct>();
                        _db = new LASDBDataContext();
                        return;
                    }

                    var codigoUnico = _currentStruct.CodigoUnico;

                    switch (tipoDocumento)
                    {
                        case Constants.DOCUMENT_TYPE_OC:
                            if (tipoDeFuturoDocumento == Constants.DOCUMENT_TYPE_FP)
                                CreateOCtoFP(codigoUnico);
                            else if (tipoDeFuturoDocumento == Constants.DOCUMENT_TYPE_EM)
                                CreateOCtoEM(codigoUnico);
                            break;
                        case Constants.DOCUMENT_TYPE_EM:
                            CreateEMtoFP(codigoUnico);
                            break;
                    }
                }
                //Regresa a la sección de pendientes y limpia la interfaz
                Documento.Visibility = Visibility.Collapsed;
                Pendientes.Visibility = Visibility.Visible;
                InputTipoDeDocumento.SelectedIndex = -1;
                GridPendientes.ItemsSource = new List<PendingStruct>();
                _db = new LASDBDataContext();
            }
            catch (Exception)
            {
                MessageBox.Show("No se pudo guardar en la base de datos");
            }
        }
        
        /// <summary>
        /// Método que se dispara al presionar el botón de cancelar,
        /// regresa al usuario a la sección de pendientes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CancelDocumentClick(object sender, RoutedEventArgs e)
        {
            Documento.Visibility = Visibility.Collapsed;
            Pendientes.Visibility = Visibility.Visible;
        }
        #endregion
        
        #endregion

        #endregion

        #endregion

        #region GUI Saldo de Proveedores
        #endregion

        #region Métodos LINQ-TO-SQL
        /// <summary>
        /// Metodo que permite obtener la lista de bodegas
        /// </summary>
        /// <param name="companyId"></param>
        /// <returns></returns>
        private List<Bodega> GetStorageRoomsFromCompany(int companyId)
        {
            List<Bodega> listaBodegas;

            try
            {
                var resultado = from bodega in _db.Bodegas
                                where bodega.IdEmpresa == companyId
                                select bodega;
                listaBodegas = resultado.ToList();
            }
            catch
            {
                return null;
            }

            return listaBodegas;
        }



        private IEnumerable<Articulo> GetProductsFromCompany(int companyId)
        {
            List<Articulo> listaDeArticulos = null;

            try
            {
                var resultado = from articulo in _db.Articulos
                                join articulosEnBodegas in _db.Bodegas_has_Articulos on articulo.IdArticulo equals
                                    articulosEnBodegas.IdArticulo
                                join bodega in _db.Bodegas on articulosEnBodegas.IdBodega equals bodega.IdBodega
                                join empresaActual in _db.Empresas on bodega.IdBodega equals empresaActual.IdEmpresa
                                where empresaActual.IdEmpresa == companyId
                                select articulo;
                listaDeArticulos = resultado.ToList();
            }
            catch
            {
                //TODO: Error al recuperar los articulos
            }
            return listaDeArticulos;
        }


        private IEnumerable<GetPendingOCResult> GetPendingOC(int companyId)
        {
            IEnumerable<GetPendingOCResult> listaDeOC = null;

            try
            {
                var resultado = _db.GetPendingOC(companyId);
                listaDeOC = resultado;
            }
            catch
            {
                return new List<GetPendingOCResult>();
            }
            return listaDeOC;
        }

        private IEnumerable<GetPendingEMResult> GetPendingEM(int companyId)
        {
            IEnumerable<GetPendingEMResult> listaDeEM;

            try
            {
                var resultado = _db.GetPendingEM(companyId);
                listaDeEM = resultado;
            }
            catch
            {
                return new List<GetPendingEMResult>();
            }
            return listaDeEM;
        }

        private IEnumerable<GetPendingFPResult> GetPendingFP(int companyId)
        {
            IEnumerable<GetPendingFPResult> listaDeFP;

            try
            {
                var resultado = _db.GetPendingFP(companyId);
                listaDeFP = resultado;
            }
            catch
            {
                return new List<GetPendingFPResult>();
            }
            return listaDeFP;
        }


        private List<PendingStruct> OcPendingStruct(int companyId)
        {
            List<PendingStruct> result;

            try
            {
                var list = GetPendingOC(companyId);
                result = (from getPendingEmResult in list
                          let resultado = (from datos in _db.DatosDocumentosCompras
                                           where datos.IdDatosDocumentosCompras == getPendingEmResult.IdDatosDocumentosCompras
                                           select datos).Single()
                          select new PendingStruct
                                     {
                                         DatosDocumentos = resultado, CodigoUnico = getPendingEmResult.IdUnicoDocumento
                                     }).ToList();
            }
            catch
            {
                return new List<PendingStruct>();
            }

            return result;
        }

        private List<PendingStruct> EmPendingStruct(int companyId)
        {
            List<PendingStruct> result;

            try
            {
                var list = GetPendingEM(companyId);
                result = (from getPendingEmResult in list
                          let resultado = (from datos in _db.DatosDocumentosCompras
                                           where datos.IdDatosDocumentosCompras == getPendingEmResult.IdDatosDocumentosCompras
                                           select datos).Single()
                          select new PendingStruct
                                     {
                                         DatosDocumentos = resultado, CodigoUnico = getPendingEmResult.IdUnicoDocumento
                                     }).ToList();
            }
            catch
            {
                return new List<PendingStruct>();
            }

            return result;
        }

        private List<PendingStruct> FpPendingStruct(int companyId)
        {
            List<PendingStruct> result = null;

            try
            {
                var list = GetPendingFP(companyId);
                result = (from getPendingEmResult in list
                          let resultado = (from datos in _db.DatosDocumentosCompras
                                           where datos.IdDatosDocumentosCompras == getPendingEmResult.IdDatosDocumentosCompras
                                           select datos).Single()
                          select new PendingStruct
                                     {
                                         DatosDocumentos = resultado, CodigoUnico = getPendingEmResult.IdUnicoDocumento
                                     }).ToList();
            }
            catch
            {
                return  new List<PendingStruct>();
            }

            return result;
        }

        /// <summary>
        /// Metodo que permite obtener la lista de proveedores
        /// </summary>
        /// <returns></returns>
        private List<Socio> LoadProveedoresSistema()
        {
            List<Socio> result = null;

            try
            {
                var queryResult = from socio in _db.Socios
                                  where socio.TipoSocio.TipoSocio1.Contains("Proveedor")
                                  select socio;
                result = queryResult.ToList();
            }
            catch (Exception)
            {
                return result;
            }
            return result;
        }


        private List<Moneda> LoadSystemCurrencies()
        {
            List<Moneda> result = null;

            try
            {
                var queryResult = from moneda in _db.Monedas
                                  select moneda;
                result = queryResult.ToList();
            }
            catch (Exception)
            {
                return result;
            }
            return result;
        }


        #region Creacion documentos Compras
        /// <summary>
        /// Metodo que permite crear una orden de compra sin documentos previos
        /// </summary>
        /// <param name="listaProductos">Lista de productos por añadir</param>
        public void CreateOC(List<InsertProduct> listaProductos)
        {

            try
            {
                var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
                var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
                var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
                var fechaEntrega = FechaEntregaDatePicker.SelectedDate;
                var totalAntesImpuesto = Convert.ToDecimal(TotalAntesImpuestoTextbox.Text);
                var impuestos = Convert.ToDecimal(ImpuestoTextBox.Text);

                // ingresa el documento de OC
                _db.InsertDocumentOC(_listaSocios[selectedPartnerIndex].IdSocio, _companyId,
                                     _listaMonedas[selectedMoneyIndex].IdMoneda, fechaContabilizacion, fechaEntrega,
                                     totalAntesImpuesto, impuestos);

                // se ingresan los productos correspondientes
                foreach (var producto in listaProductos)
                {
                    _db.InsertDocumentProduct(producto.IdArticulo, producto.IdBodega, producto.Cantidad,
                                              producto.PrecioCompra, producto.Impuesto);
                }
                MessageBox.Show("Orden de compra, guardada satisfactoriamente");
            }
            catch (Exception)
            {
                MessageBox.Show("No se pudo guardar la orden de compra");
            }

        }

        /// <summary>
        /// Metodo que permite crear una entrega de mercancias sin documentos previos
        /// </summary>
        /// <param name="listaProductos">Lista de productos por añadir</param>
        public void CreateEM(List<InsertProduct> listaProductos)
        {
            var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
            var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
            var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
            var fechaEntrega = FechaEntregaDatePicker.SelectedDate;
            var totalAntesImpuesto = Convert.ToDecimal(TotalAntesImpuestoTextbox.Text);
            var impuestos = Convert.ToDecimal(ImpuestoTextBox.Text);

            // ingresa el documento de EM
            _db.InsertDocumentEM(_listaSocios[selectedPartnerIndex].IdSocio, _companyId,
                                 _listaMonedas[selectedMoneyIndex].IdMoneda, fechaContabilizacion, fechaEntrega,
                                 totalAntesImpuesto, impuestos,"");

            // se ingresan los productos correspondientes
            foreach (var producto in listaProductos)
            {
                _db.InsertDocumentProduct(producto.IdArticulo, producto.IdBodega, producto.Cantidad,
                                          producto.PrecioCompra, producto.Impuesto);
            }

            // Se obtiene el ultimo EM insertado
            var result = _db.GetPendingEM(_companyId).OrderByDescending(x => x.IdDocumentoCompra).First();

            // Se le dice que realice la operación de insertar mercancias
            _db.InsertMerchandise(_companyId, result.IdUnicoDocumento, 0);
            MessageBox.Show("Entrada de mercancias, realizada satisfactoriamente");
        }


        /// <summary>
        /// Metodo que permite insertar un documento de Factura de proveedores sin documentos previos
        /// </summary>
        /// <param name="listaProductos">Lista de productos a insertar</param>
        public void CreateFP(List<InsertProduct> listaProductos)
        {
            var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
            var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
            var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
            var fechaEntrega = FechaEntregaDatePicker.SelectedDate;
            var totalAntesImpuesto = Convert.ToDecimal(TotalAntesImpuestoTextbox.Text);
            var impuestos = Convert.ToDecimal(ImpuestoTextBox.Text);

            // ingresa el documento de FP
            _db.InsertDocumentFP(_listaSocios[selectedPartnerIndex].IdSocio, _companyId,
                                 _listaMonedas[selectedMoneyIndex].IdMoneda, fechaContabilizacion, fechaEntrega,
                                 totalAntesImpuesto, impuestos,"");

            // se ingresan los productos correspondientes
            foreach (var producto in listaProductos)
            {
                _db.InsertDocumentProduct(producto.IdArticulo, producto.IdBodega, producto.Cantidad,
                                          producto.PrecioCompra, producto.Impuesto);
            }
            // Se obtiene el ultimo FP insertado
            var result = _db.GetPendingFP(_companyId).OrderByDescending(x => x.IdDocumentoCompra).First();

            // Se le dice que realice la operación de actualizar
            _db.UpdateMerchandise(_companyId, result.IdUnicoDocumento, 0, 0);
            MessageBox.Show("Factura de proveedores, guardada satisfactoriamente");
        }


        /// <summary>
        /// Metodo que permite crear un documento de Entrada de mercancias si existe un documento de orden de compra con anterioridad
        /// </summary>
        /// <param name="idUnicoDocumento">Codigo unico del documento anterior</param>
        public void CreateOCtoEM(string idUnicoDocumento)
        {
            var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
            var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
            var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
            var fechaEntrega = FechaEntregaDatePicker.SelectedDate;
            var totalAntesImpuesto = Convert.ToDecimal(TotalAntesImpuestoTextbox.Text);
            var impuestos = Convert.ToDecimal(ImpuestoTextBox.Text);

            // ingresa el documento de EM
            _db.InsertDocumentEM(_listaSocios[selectedPartnerIndex].IdSocio, _companyId,
                                 _listaMonedas[selectedMoneyIndex].IdMoneda, fechaContabilizacion, fechaEntrega,
                                 totalAntesImpuesto, impuestos, idUnicoDocumento);
        }



        /// <summary>
        /// Metodo que permite crear un documento de Factura de Proveedores si existe un documento de orden de compra con anterioridad
        /// </summary>
        /// <param name="idUnicoDocumento">Codigo unico del documento anterior</param>
        public void CreateOCtoFP(string idUnicoDocumento)
        {
            var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
            var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
            var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
            var fechaEntrega = FechaEntregaDatePicker.SelectedDate;
            var totalAntesImpuesto = Convert.ToDecimal(TotalAntesImpuestoTextbox.Text);
            var impuestos = Convert.ToDecimal(ImpuestoTextBox.Text);

            // ingresa el documento de FP
            _db.InsertDocumentFP(_listaSocios[selectedPartnerIndex].IdSocio, _companyId,
                                 _listaMonedas[selectedMoneyIndex].IdMoneda, fechaContabilizacion, fechaEntrega,
                                 totalAntesImpuesto, impuestos, idUnicoDocumento);
        }

        /// <summary>
        /// Metodo que permite crear un documento de Factura de Proveedores si existe un documento de Entrega de Mercancias con anterioridad
        /// </summary>
        /// <param name="idUnicoDocumento">Codigo unico del documento anterior</param>
        public void CreateEMtoFP(string idUnicoDocumento)
        {
            var selectedPartnerIndex = ProveedorComboBox.SelectedIndex;
            var selectedMoneyIndex = MonedaComboBox.SelectedIndex;
            var fechaContabilizacion = FechaContabilizacionDatePicker.SelectedDate;
            var fechaEntrega = FechaEntregaDatePicker.SelectedDate;
            var totalAntesImpuesto = Convert.ToDecimal(TotalAntesImpuestoTextbox.Text);
            var impuestos = Convert.ToDecimal(ImpuestoTextBox.Text);

            // ingresa el documento de FP
            _db.InsertDocumentFP(_listaSocios[selectedPartnerIndex].IdSocio, _companyId,
                                 _listaMonedas[selectedMoneyIndex].IdMoneda, fechaContabilizacion, fechaEntrega,
                                 totalAntesImpuesto, impuestos, idUnicoDocumento);
        } 
        #endregion

        #endregion

        #region Métodos Estáticos
        public static List<Visual> GetChildObject<T>(Visual obj, List<Visual> result) where T : FrameworkElement
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                Visual c = VisualTreeHelper.GetChild(obj, i) as FrameworkElement;
                if (c != null)
                {
                    if (c.GetType().Equals(typeof(T)))
                    {
                        result.Add(c);
                    }
                    GetChildObject<T>(c, result);
                }
            }

            return result;
        }

        public static DataGridRow GetRow(DataGrid grid, int index)
        {
            var row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
            if (row == null)
            {
                // May be virtualized, bring into view and try again.
                grid.UpdateLayout();
                grid.ScrollIntoView(grid.Items[index]);
                row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
            }
            return row;
        }


        private static object SetProperty(object containingObject, string propertyName, object newValue)
        {
            containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new[] { newValue });

            return containingObject;
        }

        

        #endregion

        /// <summary>
        /// Metodo que convierte la grid en una lista de productos insertables en la base
        /// </summary>
        /// <returns></returns>
        private List<InsertProduct> TransformGridToInsertProduct()
        {
            _gridDocumentSource.Remove(_gridDocumentSource.Last());
            var lista = _gridDocumentSource.Select(gridStruct => new InsertProduct()
                                                                     {
                                                                         Cantidad = gridStruct.Cantidad,
                                                                         IdArticulo = gridStruct.ArticuloNuevo.IdArticulo,
                                                                         IdBodega = gridStruct.BodegaFinal.IdBodega,
                                                                         Impuesto = gridStruct.Impuesto / 100,
                                                                         PrecioCompra = gridStruct.PrecioDeCompra
                                                                     }).ToList();
            return lista;
        }


        #region Eventos de la ventana
        /// <summary>
        /// Método que se dispara al seleccionar una opción del menú general
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ChangeWindow(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (sender.GetType() != (typeof(Label))) return;
            
            switch (((Label)sender).Content.ToString())
            {
                case "Inventario":
                    _parent.MostrarInventarios();
                    break;
                case "Ventas":
                    _parent.MostrarVentas();
                    break;
                case "Socios":
                    _parent.MostrarSocios();
                    break;
                case "Bancos":
                    _parent.MostrarBancos();
                    break;
                case "Compras":
                    _parent.MostrarCompras();
                    break;
            }
        }

        /// <summary>
        /// Método que se dispara al cerrar la ventana.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CloseParent(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _parent.Close();
        }
        #endregion




        private void ProveedorComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var comboBox = (ComboBox)sender;
            if (comboBox.SelectedIndex >= 0)
            {
                NombreTextBox.Text = _listaSocios[comboBox.SelectedIndex].Nombre;
            }
        }
       
    }
}
